package com.bridgeintelligent.tag.engine.mvc.service.impl;

import com.alibaba.fastjson.JSON;
import com.bridgeintelligent.tag.engine.api.*;
import com.bridgeintelligent.tag.engine.api.rsp.AnalysisAggregationResult;
import com.bridgeintelligent.tag.engine.api.rsp.AnalysisAggregationRsp;
import com.bridgeintelligent.tag.engine.core.cache.CacheConfig;
import com.bridgeintelligent.tag.engine.core.cache.CacheUtils;
import com.bridgeintelligent.tag.engine.es.base.ESQueryUtils;
import com.bridgeintelligent.tag.engine.es.model.AnalysisAggregationModel;
import com.bridgeintelligent.tag.engine.es.model.GroupItem;
import com.bridgeintelligent.tag.engine.es.query.EsQueryBuilder;
import com.bridgeintelligent.tag.engine.mvc.service.IAnalysisAggregationService;
import com.bridgeintelligent.tag.engine.mvc.service.IEsDateService;
import com.bridgeintelligent.tag.engine.mvc.service.IGroupService;
import com.bridgeintelligent.tag.engine.parse.BaseParse;
import com.bridgeintelligent.tag.utils.FieldHandler;
import com.wayneleo.quickstart.framework.ExceptionCode;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.histogram.HistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.range.DateRangeAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.range.Range;
import org.elasticsearch.search.aggregations.bucket.range.RangeAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.Avg;
import org.elasticsearch.search.aggregations.metrics.Max;
import org.elasticsearch.search.aggregations.metrics.Min;
import org.elasticsearch.search.aggregations.metrics.Sum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * xiangjialiang
 */
@Service
@Slf4j
@AllArgsConstructor
public class AnalysisAggreagtionServiceImpl implements IAnalysisAggregationService {

    final private IGroupService groupService;

    final private IEsDateService dateService;

    private static final String CUST_NUM = "cust_num";
    /**
     * 校验数字类型
     */
    final private Pattern pattern = Pattern.compile("^(\\-|\\+)?\\d+(\\.\\d+)?$");

    @Override
    public AnalysisAggregationResult getAnalysisAggregation(AnalysisAggregationModel model) throws IOException {
        AnalysisAggregationResult result = null;

        //获取标签基本信息
        DimInfo cacheInfo = CacheUtils.getCacheInfo(CacheConfig.DIM_INFO, model.getField());
        if(cacheInfo==null){
            throw new EngineException(new ExceptionCode(999,"未查询到标签"));
        }
        if (StringUtils.equals("04",cacheInfo.getClassify()) || StringUtils.equals(model.getField(),"mobile_num")){
            throw new EngineException(new ExceptionCode(999,"不支持该类标签聚合"));
        }
        //将分析指标的默认客户数字段去掉，并获取动态列标签与后缀关系
        Map<String, String> relation = dateService.symbolRelation(model.getIndexId());
        ignoreField(model,relation);
        // 如果是数值类型标签或日期类型标签
        if(StringUtils.equals(cacheInfo.getClassify(),"03") || StringUtils.equals(cacheInfo.getClassify(),"05")){
            if (CollectionUtils.isEmpty(model.getItems())){
                result =  getHistogramAggregationValue(model, cacheInfo,relation);
            }else{
                result =  getRangeAggregationValue(model, cacheInfo,relation);
            }
        }else{
            result =  getSignAggregationValue(model, cacheInfo,relation);
        }

        //对结果进行重排序
        if (StringUtils.isNotEmpty(model.getSortWord())){
            result = sortResult(result,model.getSortWord(),model.getSortType(),model.isSortFlag());
        }

        String realField = FieldHandler.addSuffixField(model.getField(),model.getDataDate(),relation);
        //如果是03数值型，计算该标签的平均值
        if (StringUtils.equals(cacheInfo.getClassify(),"03")){
            result.setFieldAvg(this.getFiledAvg(model,realField));
        }
        //查询ES里持有对应标签的人数
        result.setExistCount(this.getExistCount(model,realField));
        return result;
    }

    private AnalysisAggregationResult sortResult(AnalysisAggregationResult result,String sortWord,String sortType,boolean sortFlag){
        if (result != null && CollectionUtils.isNotEmpty(result.getData())){
            List<AnalysisAggregationResult.R> newList;
            //直接对count进行排序
            if (sortWord.equals(CUST_NUM)){
                if (sortFlag){
                    newList = result.getData().stream().sorted(Comparator.comparing(AnalysisAggregationResult.R::getCount).reversed()).collect(Collectors.toList());
                }else{
                    newList = result.getData().stream().sorted(Comparator.comparing(AnalysisAggregationResult.R::getCount)).collect(Collectors.toList());
                }
            }else{
                Map<String,List<AnalysisAggregationResult.R>> map = new HashMap<>();
                List<AnalysisAggregationResult.R> initData = new ArrayList<>();

                result.getData().forEach(e->{
                    if (CollectionUtils.isEmpty(e.getInfo())){
                        initData.add(e);
                    }else{
                        List<AnalysisAggregationResult.Info> type = e.getInfo().stream().filter(m -> m.getField().equals(sortWord)).collect(Collectors.toList());
                        if (CollectionUtils.isEmpty(type)){
                            initData.add(e);
                        }else{
                            String value ;
                            switch (sortType){
                                case "min":
                                    value = type.get(0).getMinValue();
                                    break;
                                case "max":
                                    value = type.get(0).getMaxValue();
                                    break;
                                case "avg":
                                    value = type.get(0).getAvgValue();
                                    break;
                                case "sum":
                                    value = type.get(0).getSumValue();
                                    break;
                                default:
                                    value = "0";
                            }
                            List<AnalysisAggregationResult.R> listS = map.get(value);
                            if (CollectionUtils.isEmpty(listS)){
                                List<AnalysisAggregationResult.R> ks = new ArrayList<>();
                                ks.add(e);
                                map.put(value, ks);
                            }else{
                                listS.add(e);
                                map.put(value,listS);
                            }
                        }
                    }
                });

                List  dList = new ArrayList();
                if (sortFlag){
                    List<String> keyList = map.keySet().stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
                    keyList.forEach(e->{
                        dList.addAll(map.get(e));
                    });
                    dList.addAll(initData);
                }else{
                    dList.addAll(initData);
                    List<String> keyList = map.keySet().stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
                    keyList.forEach(e->{
                        dList.addAll(map.get(e));
                    });
                }
                newList = dList;
            }
            result.setData(newList);
        }
        return result;
    }

    private AnalysisAggregationResult getHistogramAggregationValue(AnalysisAggregationModel model, DimInfo cacheInfo,Map<String, String> relation) throws IOException {
        // 筛选条件
        QueryBuilder queryBuilder;
        if (FieldHandler.FALSE.equals(model.getTimeType())){
            queryBuilder = EsQueryBuilder.buildFilter(model.getFilterGroup());
        }else{
            queryBuilder = QueryBuilders.termsQuery(FieldHandler.CUSTOMER_FLAG,model.getCustomerId());
        }
        String column = FieldHandler.addSuffixField(model.getField(),model.getDataDate(),relation);
        Double interval = null;
        DateHistogramInterval dateInterval = null;
        //查询ES中最小值最大值，计算间隔
        if (StringUtils.equals(cacheInfo.getClassify(),"03")){
            interval = groupService.getNumberInterval(column, queryBuilder,model.getIndexId());
            if(interval==null){
                throw new EngineException(new ExceptionCode(999,"未获取到标签:"+column+" 的min、max值"));
            }
        }
        if (StringUtils.equals(cacheInfo.getClassify(),"05")){
            dateInterval = groupService.getDateInterval(column,queryBuilder,model.getIndexId());
            if(dateInterval==null){
                throw new EngineException(new ExceptionCode(999,"未获取到标签:"+column+" 的min、max值"));
            }
        }
        SearchRequest request = getHistogramRequest(column, queryBuilder, cacheInfo, model, interval, dateInterval);
        return getHistogramResult(ESQueryUtils.getClient().search(request, RequestOptions.DEFAULT), model,cacheInfo,interval,dateInterval);
    }

    //这个方法之只有03，05类型才会进入
    private SearchRequest getHistogramRequest(String dimIdColumn, QueryBuilder queryBuilder, DimInfo cacheInfo, AnalysisAggregationModel model,Double interval, DateHistogramInterval dateInterval) throws IOException {
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, model.getIndexId());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder).trackTotalHits(true).size(0);
        //如果是数值类型
        if(StringUtils.equals("03", cacheInfo.getClassify())){
            searchSourceBuilder.aggregation(getNumberHistogramAggregation(model, dimIdColumn,interval));
        }else{
            searchSourceBuilder.aggregation(getDateHistogramAggregation(model, dimIdColumn,dateInterval));
        }
        return new SearchRequest(indexNameInfo.getDataDate()).source(searchSourceBuilder);
    }


    private HistogramAggregationBuilder getNumberHistogramAggregation(AnalysisAggregationModel model, String dimId,Double interval) throws IOException {
        HistogramAggregationBuilder builder =
                AggregationBuilders
                        .histogram("histogram_"+model.getField())
                        .field(dimId)
                        .interval(interval)
                        .order(BucketOrder.key(true))
                        .minDocCount(1);

        if (CollectionUtils.isNotEmpty(model.getFields())){
            model.getFields().forEach(e -> {
                builder.subAggregation(AggregationBuilders.max("max_"+e).field(model.getTrendMap().get(e)));
                builder.subAggregation(AggregationBuilders.min("min_"+e).field(model.getTrendMap().get(e)));
                builder.subAggregation(AggregationBuilders.avg("avg_"+e).field(model.getTrendMap().get(e)));
                builder.subAggregation(AggregationBuilders.sum("sum_"+e).field(model.getTrendMap().get(e)));
            });
        }
        return builder;
    }

    private DateHistogramAggregationBuilder getDateHistogramAggregation(AnalysisAggregationModel model, String dimId,DateHistogramInterval dateInterval) {

        DateHistogramAggregationBuilder builder =
                AggregationBuilders
                        .dateHistogram("histogram_"+model.getField())
                        .field(dimId)
                        .dateHistogramInterval(dateInterval)
                        .format("yyyy-MM-dd")
                        .order(BucketOrder.key(true))
                        .minDocCount(1);
        if (CollectionUtils.isNotEmpty(model.getFields())){
            model.getFields().forEach(e -> {
                builder.subAggregation(AggregationBuilders.max("max_"+e).field(model.getTrendMap().get(e)));
                builder.subAggregation(AggregationBuilders.min("min_"+e).field(model.getTrendMap().get(e)));
                builder.subAggregation(AggregationBuilders.avg("avg_"+e).field(model.getTrendMap().get(e)));
                builder.subAggregation(AggregationBuilders.sum("sum_"+e).field(model.getTrendMap().get(e)));
            });
        }
        return builder;
    }

    private AnalysisAggregationResult getHistogramResult(SearchResponse response, AnalysisAggregationModel model,DimInfo cacheInfo,Double interval,DateHistogramInterval dateInterval){

        long totalCount = response.getHits().getTotalHits().value;
        Histogram histogram = response.getAggregations().get("histogram_"+model.getField());
        List<AnalysisAggregationResult.R> result = new ArrayList<>();
        for (Histogram.Bucket entry : histogram.getBuckets()) {
            List<AnalysisAggregationResult.Info> data = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(model.getFields())){
                model.getFields().forEach(e -> {
                    Max max = entry.getAggregations().get("max_" + e);
                    Min min = entry.getAggregations().get("min_" + e);
                    Avg avg = entry.getAggregations().get("avg_" + e);
                    Sum sum = entry.getAggregations().get("sum_" + e);
                    data.add(AnalysisAggregationResult.Info.of().setField(e).setMaxValue(realValue(max.getValueAsString())).setMinValue(realValue(min.getValueAsString())).setSumValue(realValue(sum.getValueAsString())).setAvgValue(realValue(avg.getValueAsString())));
                });
            }

            String title = getTitle(cacheInfo.getClassify(),entry.getKeyAsString(),interval,dateInterval);

            result.add(AnalysisAggregationResult.R.of().setTitle(title).setCount(entry.getDocCount()).setInfo(data).setPercent(this.compute(entry.getDocCount(),totalCount)));
        }
        sort(cacheInfo.getClassify(),result);
        return AnalysisAggregationResult.of().setData(result).setDimId(cacheInfo.getDimId()).setDimName(cacheInfo.getDimName()).setTotalCount(totalCount).setClassify(cacheInfo.getClassify());
    }


    private String getTitle(String classify,String keyAsString,Double interval,DateHistogramInterval dateInterval){

        if (StringUtils.equals(classify,"03")){
            long key = Double.valueOf(keyAsString).longValue();
            long high = key + interval.longValue();
            return  key+"~"+high;
        }else{
            if(dateInterval.equals(DateHistogramInterval.YEAR)){
                DateTime.parse(keyAsString, DateTimeFormat.forPattern("yyyy-MM-dd")).plusYears(1).toString("yyyy-MM-dd");
                return keyAsString+"/"+DateTime.parse(keyAsString, DateTimeFormat.forPattern("yyyy-MM-dd")).plusYears(1).toString("yyyy-MM-dd");
            }
            if(dateInterval.equals(DateHistogramInterval.MONTH)){
                DateTime.parse(keyAsString, DateTimeFormat.forPattern("yyyy-MM-dd")).plusMonths(1).toString("yyyy-MM-dd");
                return keyAsString+"/"+DateTime.parse(keyAsString, DateTimeFormat.forPattern("yyyy-MM-dd")).plusMonths(1).toString("yyyy-MM-dd");
            }
            String inter = dateInterval.toString();
            String start = keyAsString;
            if(StringUtils.startsWith(keyAsString, "-")){
                // 最小日期
                start = "0001-01-01";
            }
            return start+"/"+DateTime.parse(keyAsString, DateTimeFormat.forPattern("yyyy-MM-dd")).plusDays(Integer.parseInt(inter.substring(0, inter.length()-1))).toString("yyyy-MM-dd");
        }

    }


    private AnalysisAggregationResult getRangeAggregationValue(AnalysisAggregationModel model, DimInfo cacheInfo,Map<String, String> relation) throws IOException {
        // 筛选条件
        QueryBuilder queryBuilder;
        if (FieldHandler.FALSE.equals(model.getTimeType())){
            queryBuilder = EsQueryBuilder.buildFilter(model.getFilterGroup());
        }else{
            queryBuilder = QueryBuilders.termsQuery(FieldHandler.CUSTOMER_FLAG,model.getCustomerId());
        }
        String column = FieldHandler.addSuffixField(model.getField(),model.getDataDate(),relation);
        SearchRequest request = getRequest(column, queryBuilder, cacheInfo, model);
        return getRangResult(ESQueryUtils.getClient().search(request, RequestOptions.DEFAULT), model,cacheInfo);
    }


    private AnalysisAggregationResult getSignAggregationValue(AnalysisAggregationModel model, DimInfo cacheInfo,Map<String, String> relation) throws IOException {
        // 筛选条件
        QueryBuilder queryBuilder;
        if (FieldHandler.FALSE.equals(model.getTimeType())){
            queryBuilder = EsQueryBuilder.buildFilter(model.getFilterGroup());
        }else{
            queryBuilder = QueryBuilders.termsQuery(FieldHandler.CUSTOMER_FLAG,model.getCustomerId());
        }
        String column = FieldHandler.addSuffixField(model.getField(),model.getDataDate(),relation);
        SearchRequest request = getRequest(column, queryBuilder, cacheInfo, model);
        return getTermResult(ESQueryUtils.getClient().search(request, RequestOptions.DEFAULT), model,cacheInfo);
    }

    private SearchRequest getRequest(String dimIdColumn, QueryBuilder queryBuilder, DimInfo cacheInfo, AnalysisAggregationModel model) {

        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, model.getIndexId());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder).trackTotalHits(true).size(0);
        //如果是数值类型
        if(StringUtils.equals("03", cacheInfo.getClassify())){
            searchSourceBuilder.aggregation(getNumberAggregation(model, dimIdColumn));
        }else if(StringUtils.equals("05", cacheInfo.getClassify())){
            searchSourceBuilder.aggregation(getDateAggregation(model, dimIdColumn));
        }else{
            searchSourceBuilder.aggregation(getTermAggregation(model, dimIdColumn,cacheInfo.getClassify()));
        }
        return new SearchRequest(indexNameInfo.getDataDate()).source(searchSourceBuilder);
    }

    private RangeAggregationBuilder getNumberAggregation(AnalysisAggregationModel model, String dimId) {
        RangeAggregationBuilder rangeBuilder = AggregationBuilders.range("range_"+model.getField()).field(dimId);
        for(GroupItem item:model.getItems()){
            String low = item.getLow();
            String high = item.getHigh();
            //不为空且不含无穷
            if (!StringUtils.isEmpty(low) && !StringUtils.isEmpty(high) && !low.contains("∞") && !high.contains("∞")){
                rangeBuilder.addRange(low+"~"+high,new Double(low),new Double(high));
            }else if (!StringUtils.isEmpty(low) && StringUtils.equals(low.trim(),"-∞")) {
                rangeBuilder.addUnboundedTo(low + "~" + high, new Double(high));
            }else if (!StringUtils.isEmpty(high) && (StringUtils.equals(high.trim(),"∞") || StringUtils.equals(high.trim(),"+∞"))){
                rangeBuilder.addUnboundedFrom(low+"~+∞",new Double(low));
            }
        }
        if (CollectionUtils.isNotEmpty(model.getFields())){
            model.getFields().forEach(e -> {
                rangeBuilder.subAggregation(AggregationBuilders.max("max_"+e).field(model.getTrendMap().get(e)));
                rangeBuilder.subAggregation(AggregationBuilders.min("min_"+e).field(model.getTrendMap().get(e)));
                rangeBuilder.subAggregation(AggregationBuilders.avg("avg_"+e).field(model.getTrendMap().get(e)));
                rangeBuilder.subAggregation(AggregationBuilders.sum("sum_"+e).field(model.getTrendMap().get(e)));
            });
        }
        return rangeBuilder;
    }


    private DateRangeAggregationBuilder getDateAggregation(AnalysisAggregationModel model, String dimId) {
        DateRangeAggregationBuilder rangeBuilder = AggregationBuilders.dateRange("range_"+model.getField()).field(dimId);
        for(GroupItem item:model.getItems()){
            String low = item.getLow();
            String high = item.getHigh();
            //不为空且不含无穷
            if (!StringUtils.isEmpty(low) && !StringUtils.isEmpty(high) && !low.contains("∞") && !high.contains("∞")){
                low = LocalDate.parse(item.getLow(), DateTimeFormatter.BASIC_ISO_DATE).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                high = LocalDate.parse(item.getHigh(), DateTimeFormatter.BASIC_ISO_DATE).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                rangeBuilder.addRange(low + "/" + high,low,high);
            }else if (!StringUtils.isEmpty(low) && StringUtils.equals(low.trim(),"-∞")) {
                high = LocalDate.parse(item.getHigh(), DateTimeFormatter.BASIC_ISO_DATE).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                rangeBuilder.addUnboundedTo(low + "/" + high, high);
            }else if (!StringUtils.isEmpty(high) && (StringUtils.equals(high.trim(),"∞") || StringUtils.equals(high.trim(),"+∞"))){
                low = LocalDate.parse(item.getLow(), DateTimeFormatter.BASIC_ISO_DATE).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                rangeBuilder.addUnboundedFrom(low+"/+∞",low);
            }
        }
        if (CollectionUtils.isNotEmpty(model.getFields())){
            model.getFields().forEach(e -> {
                rangeBuilder.subAggregation(AggregationBuilders.max("max_"+e).field(model.getTrendMap().get(e)));
                rangeBuilder.subAggregation(AggregationBuilders.min("min_"+e).field(model.getTrendMap().get(e)));
                rangeBuilder.subAggregation(AggregationBuilders.avg("avg_"+e).field(model.getTrendMap().get(e)));
                rangeBuilder.subAggregation(AggregationBuilders.sum("sum_"+e).field(model.getTrendMap().get(e)));
            });
        }
        return rangeBuilder;
    }

    private TermsAggregationBuilder getTermAggregation(AnalysisAggregationModel model, String dimId,String classify) {
        if (StringUtils.equals(classify,"01")){
            TermsAggregationBuilder termBuilder = AggregationBuilders.terms("group_"+model.getField()).field(dimId).order(BucketOrder.count(false)).size(5);
            if (CollectionUtils.isNotEmpty(model.getFields())){
                model.getFields().forEach(e -> {
                    termBuilder.subAggregation(AggregationBuilders.max("max_"+e).field(model.getTrendMap().get(e)));
                    termBuilder.subAggregation(AggregationBuilders.min("min_"+e).field(model.getTrendMap().get(e)));
                    termBuilder.subAggregation(AggregationBuilders.avg("avg_"+e).field(model.getTrendMap().get(e)));
                    termBuilder.subAggregation(AggregationBuilders.sum("sum_"+e).field(model.getTrendMap().get(e)));
                });
            }
            return termBuilder;
        }else{
            TermsAggregationBuilder termBuilder = AggregationBuilders.terms("group_"+model.getField()).field(dimId).order(BucketOrder.count(false)).size(Integer.MAX_VALUE);
            if (CollectionUtils.isNotEmpty(model.getFields())){
                model.getFields().forEach(e -> {
                    termBuilder.subAggregation(AggregationBuilders.max("max_"+e).field(model.getTrendMap().get(e)));
                    termBuilder.subAggregation(AggregationBuilders.min("min_"+e).field(model.getTrendMap().get(e)));
                    termBuilder.subAggregation(AggregationBuilders.avg("avg_"+e).field(model.getTrendMap().get(e)));
                    termBuilder.subAggregation(AggregationBuilders.sum("sum_"+e).field(model.getTrendMap().get(e)));
                });
            }
            return termBuilder;
        }
    }

    private AnalysisAggregationResult getRangResult(SearchResponse response, AnalysisAggregationModel model,DimInfo cacheInfo){
        long totalCount = response.getHits().getTotalHits().value;
        Range terms = response.getAggregations().get("range_"+model.getField());
        List<AnalysisAggregationResult.R> result = new ArrayList<>();
        for (Range.Bucket entry : terms.getBuckets()) {
            List<AnalysisAggregationResult.Info> data = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(model.getFields())){
                model.getFields().forEach(e -> {
                    Max max = entry.getAggregations().get("max_" + e);
                    Min min = entry.getAggregations().get("min_" + e);
                    Avg avg = entry.getAggregations().get("avg_" + e);
                    Sum sum = entry.getAggregations().get("sum_" + e);
                    data.add(AnalysisAggregationResult.Info.of().setField(e).setMaxValue(realValue(max.getValueAsString())).setMinValue(realValue(min.getValueAsString())).setSumValue(realValue(sum.getValueAsString())).setAvgValue(realValue(avg.getValueAsString())));
                });
            }
            result.add(AnalysisAggregationResult.R.of().setTitle(entry.getKeyAsString()).setCount(entry.getDocCount()).setInfo(data).setPercent(this.compute(entry.getDocCount(),totalCount)));
        }
        sort(cacheInfo.getClassify(),result);
        return AnalysisAggregationResult.of().setData(result).setDimId(cacheInfo.getDimId()).setDimName(cacheInfo.getDimName()).setTotalCount(totalCount).setClassify(cacheInfo.getClassify());
    }



    /**
     * 针对01描述型标签，由于没有字典项，如身份证号  手机号等 导致查询出来的数据量非常大可能会导致内存溢出，这里沟通后只返回5条数据
     * 其他标志型集合型有具体的字典项，返回所有
     */
    private AnalysisAggregationResult getTermResult(SearchResponse response, AnalysisAggregationModel model,DimInfo cacheInfo) throws IOException {
        long totalCount = response.getHits().getTotalHits().value;
        Terms terms = response.getAggregations().get("group_"+model.getField());
        List<AnalysisAggregationResult.R> result = new ArrayList<>();
        //termStr主要用于描述型标签排除前5项的数据
        List<String> termStr = new ArrayList<>();
        for (Terms.Bucket entry : terms.getBuckets()) {
            termStr.add(entry.getKeyAsString());
            List<AnalysisAggregationResult.Info> data = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(model.getFields())){
                model.getFields().forEach(e -> {
                    Max max = entry.getAggregations().get("max_" + e);
                    Min min = entry.getAggregations().get("min_" + e);
                    Avg avg = entry.getAggregations().get("avg_" + e);
                    Sum sum = entry.getAggregations().get("sum_" + e);
                    data.add(AnalysisAggregationResult.Info.of().setField(e).setMaxValue(realValue(max.getValueAsString())).setMinValue(realValue(min.getValueAsString())).setSumValue(realValue(sum.getValueAsString())).setAvgValue(realValue(avg.getValueAsString())));
                });
            }
            String title = Optional
                    .ofNullable((DimItemInfo) CacheUtils.getCacheInfo(CacheConfig.DIM_ITEM_INFO,
                            String.format(BaseParse.GROUP_FORMAT, model.getField(), entry.getKeyAsString())))
                    .map(DimItemInfo::getDimItemName)
                    .orElse(entry.getKeyAsString());
            if ("06".equals(cacheInfo.getClassify())){
                title = joinStr(title,entry.getKeyAsString());
            }
            result.add(AnalysisAggregationResult.R.of().setTitle(title).setCount(entry.getDocCount()).setInfo(data).setPercent(this.compute(entry.getDocCount(),totalCount)));
        }

        //如果是描述性标签，计算"其他"组的相关信息。处理做法是排除前五种数据
        if(StringUtils.equals("01",cacheInfo.getClassify())){
            result.add(otherResult(model,cacheInfo,termStr,totalCount));
        }
        return AnalysisAggregationResult.of().setData(result).setDimName(cacheInfo.getDimName()).setDimId(cacheInfo.getDimId()).setTotalCount(totalCount).setClassify(cacheInfo.getClassify());
    }

    public AnalysisAggregationResult.R otherResult(AnalysisAggregationModel model,DimInfo cacheInfo,List<String> termStr,long totalCount) throws IOException {
     log.info("termStr:{}", JSON.toJSON(termStr));
        // 封装查询条件
        QueryBuilder initBuilder;
        if (FieldHandler.FALSE.equals(model.getTimeType())){
            initBuilder = EsQueryBuilder.buildFilter(model.getFilterGroup());
        }else{
            initBuilder = QueryBuilders.termQuery(FieldHandler.CUSTOMER_FLAG,model.getCustomerId());
        }
        Map<String, String> relation = dateService.symbolRelation(model.getIndexId());
        String column = FieldHandler.addSuffixField(model.getField(),model.getDataDate(),relation);
        QueryBuilder queryBuilder  = QueryBuilders.boolQuery()
                .must(initBuilder)
                .mustNot(QueryBuilders.termsQuery(column,termStr));

        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, model.getIndexId());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder).trackTotalHits(true).size(0);
        //设置聚合函数
        if (CollectionUtils.isNotEmpty(model.getFields())){
            model.getFields().forEach(e -> {
                searchSourceBuilder.aggregation(AggregationBuilders.max("max_"+e).field(model.getTrendMap().get(e)));
                searchSourceBuilder.aggregation(AggregationBuilders.min("min_"+e).field(model.getTrendMap().get(e)));
                searchSourceBuilder.aggregation(AggregationBuilders.avg("avg_"+e).field(model.getTrendMap().get(e)));
                searchSourceBuilder.aggregation(AggregationBuilders.sum("sum_"+e).field(model.getTrendMap().get(e)));
            });
        }
        //构造searchRequest
        SearchRequest searchRequest = new SearchRequest(indexNameInfo.getDataDate()).source(searchSourceBuilder);
        //响应结果response
        SearchResponse response = ESQueryUtils.getClient().search(searchRequest, RequestOptions.DEFAULT);
        //总人数1
        long totalCount1 = response.getHits().getTotalHits().value;

        Aggregations aggregations = response.getAggregations();
        List<AnalysisAggregationResult.Info> data = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(model.getFields())){
            model.getFields().forEach(e -> {
                Max max = aggregations.get("max_" + e);
                Min min = aggregations.get("min_" + e);
                Avg avg = aggregations.get("avg_" + e);
                Sum sum = aggregations.get("sum_" + e);
                data.add(AnalysisAggregationResult.Info.of().setField(e).setMaxValue(realValue(max.getValueAsString())).setMinValue(realValue(min.getValueAsString())).setSumValue(realValue(sum.getValueAsString())).setAvgValue(realValue(avg.getValueAsString())));
            });
        }
        return AnalysisAggregationResult.R.of().setTitle("其他").setCount(totalCount1).setInfo(data).setPercent(this.compute(totalCount1,totalCount));
    }

    private  void ignoreField(AnalysisAggregationModel model,Map<String, String> relation){

        if (CollectionUtils.isNotEmpty(model.getFields())){
            List<String> list = model.getFields().stream().filter(e -> !e.equals(CUST_NUM)).collect(Collectors.toList());
            model.setFields(list);
            if (!CollectionUtils.isEmpty(list)){
                //获取动态列的时间后缀
                Map map = new HashMap();
                list.forEach(e->{
                    map.put(e, FieldHandler.addSuffixField(e,model.getDataDate(),relation));
                });
                model.setTrendMap(map);
            }
        }
    }

    @Override
    public long getExistCount(AnalysisAggregationModel model,String field) throws IOException {
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, model.getIndexId());
        SearchRequest searchRequest = new SearchRequest(indexNameInfo.getDataDate());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder;
        if (FieldHandler.FALSE.equals(model.getTimeType())){
            queryBuilder = QueryBuilders.boolQuery()
                    .must(EsQueryBuilder.buildFilter(model.getFilterGroup()))
                    .must(QueryBuilders.existsQuery(field));
        }else{
            queryBuilder = QueryBuilders.boolQuery()
                    .must(QueryBuilders.termsQuery(FieldHandler.CUSTOMER_FLAG,model.getCustomerId()))
                    .must(QueryBuilders.existsQuery(field));
        }
        sourceBuilder.query(queryBuilder).trackTotalHits(true).size(0);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = ESQueryUtils.getClient().search(searchRequest, RequestOptions.DEFAULT);
        if (searchResponse != null){
            SearchHits hits = searchResponse.getHits();
            if (hits != null){
                TotalHits totalHits = hits.getTotalHits();
                if (totalHits != null){
                    return totalHits.value;
                }
            }
        }
        return 0L;
    }

    public String getFiledAvg(AnalysisAggregationModel model,String realField) throws IOException {
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, model.getIndexId());
        SearchRequest searchRequest = new SearchRequest(indexNameInfo.getDataDate());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder;
        if (FieldHandler.FALSE.equals(model.getTimeType())){
            queryBuilder = EsQueryBuilder.buildFilter(model.getFilterGroup());
        }else{
            queryBuilder = QueryBuilders.termsQuery(FieldHandler.CUSTOMER_FLAG,model.getCustomerId());
        }
        sourceBuilder.query(queryBuilder).trackTotalHits(true).size(0);
        sourceBuilder.aggregation(AggregationBuilders.avg("avg_"+model.getField()).field(realField));
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = ESQueryUtils.getClient().search(searchRequest, RequestOptions.DEFAULT);
        if (searchResponse != null && searchResponse.getAggregations() != null){
            Avg avg = searchResponse.getAggregations().get("avg_" + model.getField());
            if (avg != null){
                return realValue(avg.getValueAsString());
            }
        }
        return "0.00";
    }


    public long getAllCount(String indexId) throws IOException {
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, indexId);
        SearchRequest searchRequest = new SearchRequest(indexNameInfo.getDataDate());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchAllQuery()).trackTotalHits(true).size(0);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = ESQueryUtils.getClient().search(searchRequest, RequestOptions.DEFAULT);
        if (searchResponse != null){
            SearchHits hits = searchResponse.getHits();
            if (hits != null){
                TotalHits totalHits = hits.getTotalHits();
                if (totalHits != null){
                    return totalHits.value;
                }
            }
        }
        return 0l;
    }

    public long getQueryCount(AnalysisAggregationModel model) throws IOException {
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, model.getIndexId());
        SearchRequest searchRequest = new SearchRequest(indexNameInfo.getDataDate());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder;
        if (FieldHandler.FALSE.equals(model.getTimeType())){
            log.info("=====>校验动态false");
            queryBuilder = EsQueryBuilder.buildFilter(model.getFilterGroup());
        }else{
            log.info("=====>校验静态true");
            queryBuilder = QueryBuilders.termsQuery(FieldHandler.CUSTOMER_FLAG,model.getCustomerId());
        }
        log.info("=====>AnalysisCount筛选条件为：{}",queryBuilder);
        sourceBuilder.query(queryBuilder).trackTotalHits(true).size(0);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = ESQueryUtils.getClient().search(searchRequest, RequestOptions.DEFAULT);
        if (searchResponse != null){
            SearchHits hits = searchResponse.getHits();
            if (hits != null){
                TotalHits totalHits = hits.getTotalHits();
                if (totalHits != null){
                    log.info("=====>AnalysisCount筛选数量为：{}",totalHits.value);
                    return totalHits.value;
                }
            }
        }
        return 0l;


    }

    @Override
    public AnalysisAggregationRsp getPercent(AnalysisAggregationModel model) throws IOException {
        //获取ES总数据量
        long allCount = this.getAllCount(model.getIndexId());
        long totalCount = this.getQueryCount(model);
        String percent = compute(totalCount,allCount);
        return AnalysisAggregationRsp.of().setCode(0).setMsg("查询成功").setAllCount(allCount).setTotalCount(totalCount).setPercent(percent);
    }


    /**
     * 计算真实value值
     * @param valueStr
     * @return
     */
    private String realValue(String valueStr){
        valueStr = Optional.ofNullable(valueStr).orElse("0.00");
        if (pattern.matcher(valueStr).matches()){
            return String.valueOf(new BigDecimal(valueStr).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
        }else if(valueStr.contains("Infinity")){
            return "0.00";
        }else{
            return new BigDecimal(valueStr).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString();
        }
    }



    /**
     * 计算百分比
     * @param k1
     * @param k2
     * @return
     */
    public String compute(long k1,long k2){
        BigDecimal n1 = BigDecimal.valueOf(k1);
        BigDecimal n2 = BigDecimal.valueOf(k2);
        if (k2 == 0l || k1 == 0l){
            return "0%";
        }
        return n1.multiply(new BigDecimal("100")).divide(n2,2,BigDecimal.ROUND_HALF_UP)+"%";
    }

    public String joinStr(String key,String value){
        StringBuffer buffer = new StringBuffer();
        buffer.append(key).append("(").append(value).append(")");
        return buffer.toString();
    }

    private void sort(String classify, List<AnalysisAggregationResult.R> data) {
        if(StringUtils.equals(classify,"03")){
            data.sort((o1, o2) -> {
                Double v1 = getValue(o1.getTitle());
                Double v2 = getValue(o2.getTitle());
                return v1.compareTo(v2);
            });
        }
        if(StringUtils.equals(classify,"05")){
            data.sort((o1, o2) -> {
                String title1 = o1.getTitle();
                String title2 = o2.getTitle();
                if(StringUtils.contains(title1,"-∞")||StringUtils.contains(title2,"+∞")){
                    return -1;
                }
                if(StringUtils.contains(title1,"+∞")||StringUtils.contains(title2,"-∞")){
                    return 1;
                }
                return StringUtils.compare(title1, title2);
            });
        }
    }

    private Double getValue(String D1) {
        String[] array = D1.split("~");
        if(D1.indexOf("-")==0){
            if(StringUtils.equals("-∞",array[0])){
                return Double.MIN_VALUE;
            }
            return Double.parseDouble(array[0]);
        }else{
            if(StringUtils.equals("+∞",array[0]) || StringUtils.equals("∞",array[0])){
                return Double.MAX_VALUE;
            }
            return Double.parseDouble(array[0]);
        }
    }


}
